package cn.ryh.netty.websocket.server;

import cn.ryh.netty.websocket.handler.ProtocolSelectorHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;

/**
 * NettyServer
 * @author Raoyh
 */
@Slf4j
public class NettyServer {

    private final Integer port;

    public NettyServer(Integer port) {
        this.port = port;
    }

    public void createNetty() {
        //bossGroup作为boss,接收传入连接
        EventLoopGroup bossGroup = null;
        EventLoopGroup workerGroup = null;

        /**
         * 宏定义
         */
        bossGroup = new NioEventLoopGroup(32);
        workerGroup = new NioEventLoopGroup(64);
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup);
            b.channel(NioServerSocketChannel.class);
            b.childOption(ChannelOption.TCP_NODELAY, true);
            //服务初始化通道处理
            b.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline pp = ch.pipeline();
                    pp.addLast(new ProtocolSelectorHandler());
                }
            });
            //等待处理的队列大小
            b.option(ChannelOption.SO_BACKLOG, 256);
            //Boss线程内存池配置.
            b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                //Work线程内存池配置.
                .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .childOption(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator());
            //是否启用心跳保活机制。在双方TCP套接字建立连接后（即都进入ESTABLISHED状态）并且在两个小时左右上层没有任何数据传输的情况下，这套机制才会被激活。
            b.childOption(ChannelOption.SO_KEEPALIVE, true);
            // 绑定端口
            ChannelFuture f = b.bind(port).sync();
            //sync()会同步等待连接操作结果，用户线程将在此wait()，直到连接操作完成之后，线程被notify(),用户代码继续执行
            //closeFuture()当Channel关闭时返回一个ChannelFuture,用于链路检测
            log.info("[NETTY][CREATE][PORT = {}]  ...... START ......", port);
            f.channel().closeFuture().sync();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            //资源优雅释放
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
